package com.ds.infrastructure.hyperspace.console.service.impl;

import com.ds.infrastructure.hyperspace.console.common.methodlock.MethodLockId;
import com.ds.infrastructure.hyperspace.console.constants.ConsoleConstant;
import com.ds.infrastructure.hyperspace.console.dto.deploydata.DeployDataDTO;
import com.ds.infrastructure.hyperspace.console.dto.deploydata.HostGroupDTO;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbDeployActiveTaskEnum;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbDeployInstallTaskEnum;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbDeployNodeEnum;
import com.ds.infrastructure.hyperspace.console.entity.enums.TbPublicEnum;
import com.ds.infrastructure.hyperspace.console.entity.page.TbPageWhere;
import com.ds.infrastructure.hyperspace.console.entity.table.TbDeployActiveTask;
import com.ds.infrastructure.hyperspace.console.entity.table.TbDeployConfig;
import com.ds.infrastructure.hyperspace.console.entity.table.TbDeployInstallTask;
import com.ds.infrastructure.hyperspace.console.entity.table.TbDeployNode;
import com.ds.infrastructure.hyperspace.console.exceptions.HyperspaceException;
import com.ds.infrastructure.hyperspace.console.service.inf.*;
import com.ds.infrastructure.hyperspace.console.utils.FastJsonUtil;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: yaozhendong
 * @create: 2019-10-22 11:59
 **/

@Service
public class DeployManageService implements IDeployManageService {

    @Autowired
    IDeployConfigService iDeployConfigService;
    @Autowired
    IDeployInstallTaskService iDeployInstallTaskService;
    @Autowired
    IDeployNodeService iDeployNodeService;
    @Autowired
    IDeployActiveTaskService iDeployActiveTaskService;

    @Override
    public Long deploy(MethodLockId newId, TbDeployConfig entity, List<HostGroupDTO> hostGroupDTOList) {
        //升级配置版本
        iDeployConfigService.updateVersion(entity);
        Long taskId = createDeployTask(entity, hostGroupDTOList);
        createDeployNode(taskId, hostGroupDTOList);
        updateTaskState(taskId);
        return taskId;
    }

    private void updateTaskState(Long taskId) {
        TbDeployInstallTask tbDeployInstallTask = new TbDeployInstallTask();
        tbDeployInstallTask.setId(taskId);
        tbDeployInstallTask.setExecuteState(TbDeployInstallTaskEnum.EXECUTE_STATE.CREATE_NODE.code);
        iDeployInstallTaskService.update(tbDeployInstallTask);
    }

    private void createDeployNode(Long taskId, List<HostGroupDTO> hostGroupDTOList) {
        List<TbDeployNode> nodeList = new ArrayList<>();
        for (HostGroupDTO hostGroup : hostGroupDTOList) {
            hostGroup.getHosts().forEach(item -> {
                TbDeployNode node = new TbDeployNode();
                node.setDeployTaskId(taskId);
                node.setHostGroupId(hostGroup.getId());
                node.setHostGroupName(hostGroup.getGroupName());
                node.setHost(item.getHostName());
                node.setHostType(item.getHostType());
                node.setDeployState(TbDeployNodeEnum.DEPLOY_STATE.INIT.code);
                node.setActiveState(TbDeployNodeEnum.ACTIVE_STATE.INIT.code);
                node.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
                nodeList.add(node);
            });
        }
        iDeployNodeService.insertList(nodeList);
    }

    private Long createDeployTask(TbDeployConfig entity, List<HostGroupDTO> hostGroupDTOList) {
        TbDeployInstallTask tbDeployInstallTask = new TbDeployInstallTask();
        tbDeployInstallTask.setStageId(entity.getStageId());
        tbDeployInstallTask.setEnvironmentId(entity.getEnvironmentId());
        tbDeployInstallTask.setDeployConfigId(entity.getId());
        tbDeployInstallTask.setExecuteState(TbDeployInstallTaskEnum.EXECUTE_STATE.INIT.code);
        tbDeployInstallTask.setCompleteState(TbPublicEnum.TASK_COMPLETE_STATE.INIT.value);
        List<String> hostGroupIds = hostGroupDTOList.stream().map(HostGroupDTO::getId).collect(Collectors.toList());
        tbDeployInstallTask.setHostGroupIds(StringUtils.join(hostGroupIds, ConsoleConstant.HOST_GROUP_SEPARATOR));
        tbDeployInstallTask.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        iDeployInstallTaskService.save(tbDeployInstallTask);
        return tbDeployInstallTask.getId();
    }

    @Override
    public List<HostGroupDTO> getHostGroupDTOList(TbDeployConfig entity, List<String> hostGroupIds) {
        if (hostGroupIds == null || hostGroupIds.isEmpty()) {
            throw new HyperspaceException("hostGroupIds == null");
        }
        DeployDataDTO deployDataDTO = getDeployDataDTO(entity);
        if (deployDataDTO == null) {
            throw new HyperspaceException("deployDataDTO==null");
        }
        if (deployDataDTO.getHostGroups() == null || deployDataDTO.getHostGroups().isEmpty()) {
            throw new HyperspaceException("HostGroups为空,deployConfigId=" + entity.getId());
        }
        List<HostGroupDTO> hostGroupDTOList = new ArrayList<>();
        for (String hostGroupId : hostGroupIds) {
            Optional<HostGroupDTO> first = deployDataDTO.getHostGroups().stream().filter(item -> item.getId().equals(hostGroupId)).findFirst();
            if (!first.isPresent()) {
                throw new HyperspaceException("没有找到对应的HostGroup, hostGroupId=" + hostGroupId);
            }
            HostGroupDTO hostGroupDTO = first.get();
            if (hostGroupDTO.getHosts() == null || hostGroupDTO.getHosts().isEmpty()) {
                throw new HyperspaceException("当前HostGroup的Host集合为空,HostGroupName=" + hostGroupDTO.getGroupName());
            }
            hostGroupDTOList.add(first.get());

        }
        return hostGroupDTOList;
    }

    @Override
    public Long active(Long deployTaskId, List<String> hostGroupIds) {
        TbDeployInstallTask tbDeployInstallTask = iDeployInstallTaskService.get(deployTaskId);
        if (tbDeployInstallTask == null) {
            throw new HyperspaceException("TbDeployTask中没有找到对应的记录 id=" + deployTaskId);
        }
        if (!TbPublicEnum.TASK_COMPLETE_STATE.COMPLETE.value.equals(tbDeployInstallTask.getCompleteState())) {
            throw new HyperspaceException("部署任务没有完成，id=" + deployTaskId);
        }
        List<String> deployHostGroupIds = Arrays.asList(StringUtils.split(tbDeployInstallTask.getHostGroupIds(), ConsoleConstant.HOST_GROUP_SEPARATOR));
        hostGroupIds.forEach(item -> {
            if (!deployHostGroupIds.contains(item)) {
                throw new HyperspaceException("没有找到对应的hostGroupId,deployTaskId=" + deployTaskId + ";hostGroupId=" + item);
            }
        });
        return createActiveTask(tbDeployInstallTask, hostGroupIds);
    }

    @Override
    public void executeDeployTask(Long taskId) {
        TbDeployInstallTask tbDeployInstallTask = iDeployInstallTaskService.get(taskId);
        if (TbPublicEnum.TASK_COMPLETE_STATE.COMPLETE.value.equals(tbDeployInstallTask.getCompleteState())) {
            return;
        }
        executeDeployTaskForDeployNode(taskId);
        updateStateForDeployTask(tbDeployInstallTask);
    }

    @Override
    public void executeActiveTask(Long taskId) {
        TbDeployActiveTask tbDeployActiveTask = iDeployActiveTaskService.get(taskId);
        if (TbPublicEnum.TASK_COMPLETE_STATE.COMPLETE.value.equals(tbDeployActiveTask.getCompleteState())) {
            return;
        }
        executeActiveTaskForDeployNode(tbDeployActiveTask);
        updateStateForActiveTask(tbDeployActiveTask);
    }

    @Override
    public List<TbDeployNode> getDeployNode(Long deployTaskId, Boolean hostGroupIsActive) {
        TbDeployNode where = new TbDeployNode();
        where.setDeployTaskId(deployTaskId);
        where.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        List<TbDeployNode> tbDeployNodeList = iDeployNodeService.getList(where, null, TbPageWhere.newPage4All());
        if (tbDeployNodeList.isEmpty()) {
            return tbDeployNodeList;
        }
        if (BooleanUtils.isFalse(hostGroupIsActive)) {
            return tbDeployNodeList;
        }
        List<TbDeployNode> activeNodeList = new ArrayList<>();
        for (TbDeployNode item : tbDeployNodeList) {
            if (!TbDeployNodeEnum.ACTIVE_STATE.SUCCESS.code.equals(item.getActiveState())) {
                continue;
            }
            activeNodeList.add(item);
        }
        return activeNodeList;
    }

    private void updateStateForActiveTask(TbDeployActiveTask tbDeployActiveTask) {
        TbDeployActiveTask entity = new TbDeployActiveTask();
        entity.setId(tbDeployActiveTask.getId());
        entity.setExecuteState(TbDeployActiveTaskEnum.EXECUTE_STATE.SUCCESS.code);
        entity.setCompleteState(TbPublicEnum.TASK_COMPLETE_STATE.COMPLETE.value);
        iDeployActiveTaskService.update(entity);
    }

    private void executeActiveTaskForDeployNode(TbDeployActiveTask tbDeployActiveTask) {
        if (StringUtils.isBlank(tbDeployActiveTask.getHostGroupIds())) {
            throw new HyperspaceException("HostGroupIds is empty TbDeployActiveTask id=" + tbDeployActiveTask.getId());
        }
        List<String> hostGroupIds = Arrays.asList(StringUtils.split(tbDeployActiveTask.getHostGroupIds(), ConsoleConstant.HOST_GROUP_SEPARATOR));
        TbDeployNode where = new TbDeployNode();
        where.setDeployTaskId(tbDeployActiveTask.getDeployInstallTaskId());
        where.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        List<TbDeployNode> tbDeployNodeList = iDeployNodeService.getList(where, null, TbPageWhere.newPage(0, Integer.MAX_VALUE));
        for (TbDeployNode item : tbDeployNodeList) {
            if (!hostGroupIds.contains(item.getHostGroupId())) {
                continue;
            }
            TbDeployNode record = new TbDeployNode();
            record.setId(item.getId());
            record.setActiveTaskId(tbDeployActiveTask.getId());
            record.setActiveState(TbDeployNodeEnum.ACTIVE_STATE.SUCCESS.code);
            iDeployNodeService.update(record);
        }
    }


    private void updateStateForDeployTask(TbDeployInstallTask tbDeployInstallTask) {
        TbDeployInstallTask entity = new TbDeployInstallTask();
        entity.setId(tbDeployInstallTask.getId());
        entity.setExecuteState(TbDeployInstallTaskEnum.EXECUTE_STATE.SUCCESS.code);
        entity.setCompleteState(TbPublicEnum.TASK_COMPLETE_STATE.COMPLETE.value);
        iDeployInstallTaskService.update(entity);
    }

    private void executeDeployTaskForDeployNode(Long taskId) {
        TbDeployNode where = new TbDeployNode();
        where.setDeployTaskId(taskId);
        where.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        List<TbDeployNode> tbDeployNodeList = iDeployNodeService.getList(where, null, TbPageWhere.newPage(0, Integer.MAX_VALUE));
        tbDeployNodeList.forEach(item -> {
            TbDeployNode record = new TbDeployNode();
            record.setId(item.getId());
            record.setDeployState(TbDeployNodeEnum.DEPLOY_STATE.SUCCESS.code);
            iDeployNodeService.update(record);
        });
    }

    private Long createActiveTask(TbDeployInstallTask tbDeployInstallTask, List<String> hostGroupIds) {
        TbDeployActiveTask tbDeployActiveTask = new TbDeployActiveTask();
        tbDeployActiveTask.setStageId(tbDeployInstallTask.getStageId());
        tbDeployActiveTask.setEnvironmentId(tbDeployInstallTask.getEnvironmentId());
        tbDeployActiveTask.setDeployInstallTaskId(tbDeployInstallTask.getId());
        tbDeployActiveTask.setExecuteState(TbDeployActiveTaskEnum.EXECUTE_STATE.INIT.code);
        tbDeployActiveTask.setCompleteState(TbPublicEnum.TASK_COMPLETE_STATE.INIT.value);
        tbDeployActiveTask.setHostGroupIds(StringUtils.join(hostGroupIds, ","));
        tbDeployActiveTask.setGmtIsDeleted(TbPublicEnum.GMD_IS_DEL.NO.code);
        iDeployActiveTaskService.save(tbDeployActiveTask);
        return tbDeployActiveTask.getId();
    }

    private DeployDataDTO getDeployDataDTO(TbDeployConfig entity) {
        if (StringUtils.isBlank(entity.getConfigData())) {
            return null;
        }
        return FastJsonUtil.deserialize(entity.getConfigData(), DeployDataDTO.class);
    }

}
